/*
 * case_test.h
 *
 *  Created on: 12-09-2012
 *      Author: mith
 */

#ifndef CASE_H_TEST
#define CASE_H_TEST

// BASIC LIBLARIES
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<math.h>
#include<time.h>
// MY LIBRARIES
#include "mros-v42.h"
#include "rootGSL.h"

namespace case_test
{

const unsigned N_PAR = 2;
const unsigned N_PAR_INT = 0;
const unsigned N_VAR = 2;
const char OUTPUT_FILE[] = "test.dat";
const char OUTPUT_FILE_GNUPLOT[] = "test.gnu";

class Par : public Parameters {
	private:
		double a;
		double b;

	public:

		Par(double a, double b) : a(a), b(b) {}
		~Par(){}
		Par(Par& other) : a(other.a), b(other.b) {}

		double get_a() const { return a; };
		double get_b() const { return b; };

		void set_a(double d) { a=d; };
		void set_b(double d) { b=d; };

		void print(FILE *file=stdout) const;
		void print_verboten(FILE *file=stdout) const;
		void print_label(FILE *file=stdout) const;
};

class Var : public Variables {

	private:
		int NtabD; // counter for tabD double table

		double *tabD;

		enum labelD {_x0, _x1};

	public:

		Var() : NtabD(-1) {}
		Var(unsigned n) : NtabD((int)n) { tabD = new double[n]; zeroAll(); }
		~Var() { if(NtabD != -1) { delete[] tabD; NtabD = -1; } }
		Var(Var& other) : NtabD(other.NtabD) {
			if(NtabD > 0) {
				tabD = new double[NtabD];
				for(int i=0; i<NtabD; i++) { tabD[i] = other.tabD[i]; }
			}
		}
		double &operator[](int i) {
			if(i < NtabD && i >= 0) return tabD[i];
			else exit(EXIT_FAILURE);
		}
		const double &operator[](int i) const {
			if(i < NtabD && i >= 0) return tabD[i];
			else exit(EXIT_FAILURE);
		}
		Var &operator=(const Var &rhs) {
			releaseDoubles();
			NtabD = rhs.getNtabD();
			if(NtabD > 0) {
				tabD = new double[NtabD];
				for(int i=0; i<NtabD; i++) { tabD[i] = rhs.tabD[i]; }
			}
			return *this;
		  }

		void setNoOfDoubles(unsigned n) { NtabD = (int)n; if(n > 0 ) { tabD = new double[n]; } }
		void releaseDoubles() { if(NtabD != -1) { delete[] tabD; NtabD = -1; } }

		double get_x0() { return tabD[_x0]; }
		double get_x1() { return tabD[_x1]; }

		//int getNtabD() { return NtabD; }
		int getNtabD() const { return NtabD; }

		void set_x0(double d) { tabD[_x0] = d; }
		void set_x1(double d) { tabD[_x1] = d; }

		void shake(double d=1e-6) {
			for(int i=0; i<NtabD; i++) { tabD[i] += (2.*frand()-1.)*d; }
		}

		void print(FILE *file=stdout) const;
		void print_verboten(FILE *file=stdout) const;
		void print_label(FILE *file=stdout) const;

		void zeroAll() {
			for(int i=0; i<NtabD; i++) { tabD[i] = 0.; }
		}
};

class Res : public Result {
	private:
		int n;
		Variables *V;

	public:
		Res(int n) : n(n) { if(n>0) { V = new Var(n); } else { exit(EXIT_FAILURE); } }
		~Res() { delete V; }

		void set(gsl_multiroot_fsolver *s);

		void print(FILE *file=stdout) const;
		void print_verboten(FILE *file=stdout) const;
		void print_label(FILE *file=stdout) const;

		//Variables* get_V(){ return V; }
};

// FUNKCTION (only declaration)
int function(const gsl_vector * x, void *params, gsl_vector * f);

void example();

} // end of namespace case_test
#endif /* CASE_H_ */
